package com.zcp;


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * (java工程测试)主要用来测试从手机sd卡中批量下载文件。
 * 
 * @author Administrator
 */
public class SendSMS {

    private static String path = "/sdcard/pcsuit";

    public static void main(String[] args) {
        // 重定向端口
        try {
            Runtime.getRuntime()
                    .exec("E:\\android-sdk-windows\\tools\\adb.exe forward tcp:8849 tcp:8849");
            Runtime.getRuntime()
                    .exec("E:\\android-sdk-windows\\tools\\adb.exe forward tcp:8851 tcp:8851");

            Runtime.getRuntime()
                    .exec("E:\\android-sdk-windows\\tools\\adb.exe forward tcp:8852 tcp:8852");
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            SocketChannel controlChannel = getSocketConnection(8849);
            String getSdcardInfo = "<?xml version=\"1.0\" encoding=\"utf-8\"?><root><action>SendSms</action><data><item><sendToPhone>13850143652</sendToPhone></item><message>hello xue</message>"
                    + "</data></root>";
            sendData(controlChannel, getSdcardInfo);
            String result = writeDataToFile(controlChannel, 30);
            System.out.println(result+"////result///");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

   
    /**
     * 获取发送下载文件命令
     * 
     * @param port
     * @param path
     * @return
     */
    private static String getDownFileMessage(int port, String path) {

        String message = "<?xml version=\"1.0\" encoding=\"utf-8\"?><root><action>LoadFile</action><data><filePath>"
                + path + "</filePath><key>" + port + "</key></data></root>";
        return message;
    }

    
    /**
     * 获取连接端口。
     * 
     * @param port
     * @return
     * @throws IOException
     */
    private static SocketChannel getSocketConnection(int port) throws IOException {
        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", port);
        // 生成一个socketchannel
        SocketChannel sc = SocketChannel.open();
        // 连接到server
        sc.connect(addr);
        while (!sc.finishConnect())
            ;
        return sc;
    }

    /**
     * 发送数据。
     * 
     * @param sc
     * @param value
     */
    public static boolean sendData(SocketChannel sc, String value) {
        try {

            ByteBuffer w_buff = ByteBuffer.allocate(value.length() * 2);
            w_buff.clear();
            w_buff.put(value.getBytes("utf-8"));
            w_buff.flip();
            EchoToService(sc, w_buff);
            w_buff.clear();
            return true;
        } catch (IOException ioe) {
            ioe.printStackTrace();
            return false;
        }
    }

    public static void EchoToService(SocketChannel sc, ByteBuffer write_buff) throws IOException {
        while (write_buff.hasRemaining())
            sc.write(write_buff);
    }

    /**
     * 读取通道中数据，设置超时时间为second秒。
     * 
     * @param sc
     * @param second超时时间。
     * @return
     */
    public static String writeDataToFile(final SocketChannel sc, int second) {

        String result = null;
        ExecutorService executor = Executors.newSingleThreadExecutor();
        FutureTask<String> future = new FutureTask<String>(new Callable<String>() {
            public String call() {
                // 真正的任务在这里执行，这里的返回值类型为String，可以为任意类型
                return getDataFromChannel(sc);
            }
        });
        executor.execute(future);
        // 在这里可以做别的任何事情
        try {
            result = future.get(second, TimeUnit.SECONDS); // 取得结果，同时设置超时执行时间为6秒。同样可以用future.get()，不设置执行超时时间取得结果
        } catch (InterruptedException e) {
            e.printStackTrace();
            future.cancel(true);
        } catch (ExecutionException e) {
            e.printStackTrace();
            future.cancel(true);
        } catch (TimeoutException e) {
            e.printStackTrace();
            future.cancel(true);
        } finally {
            executor.shutdown();
        }
        return result;

    }

    private static final String ENDTAG = "</root>";

    /**
     * 把通道中数据读取到文件流中(如果文件太长，会分几次发送，所以这边要增加处理)。 1：修改解决分包读取问题。
     * 2：解决结束标识符号</root>被分开读取问题。 2：由于缓存中文被分开读取问题。
     * 
     * @param sc
     * @param toFile
     */
    public static String getDataFromChannel(SocketChannel sc) {
        ByteBuffer r_buff = ByteBuffer.allocate(1024);
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        try {
            r_buff.clear();
            int size = 0;
            boolean close = false;
            while (!close) {
                while ((size = sc.read(r_buff)) > 0) {
                    // 确保r_buff可读
                    r_buff.flip();
                    byteOut.write(r_buff.array(), 0, size);
                    // </root> 有可能会被分开读取（由于缓存大小限制是分开读取），所以需要增加判断。
                    byteOut.flush();
                    if ((byteOut.toString("utf-8").indexOf(ENDTAG) != -1)) {
                        close = true;
                        r_buff.clear();
                        break;
                    }
                    r_buff.clear();
                }
            }
            close = false;

        } catch (Exception e) {
            e.printStackTrace();
        }
        String result = null;
        try {
            byteOut.flush();
            result = byteOut.toString("utf-8");
            byteOut.close();
            byteOut = null;
            r_buff = null;
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return result;

    }

    /**
     * 获取正则表达式数据，比如regularKey是action,那么就是获取<action>AppManager</action><action>hi
     * </action> 中的AppManager和hi，获取所有的数据。
     * 
     * @param regularKey 正则表达式的key。
     * @param source 数据源。
     * @return 如果没有这个数据那么就返回空链表。
     */
    public static LinkedList<String> getRegular(String regularKey, String source, boolean replay) {
        LinkedList<String> result = new LinkedList<String>();
        if (replay) {
            source = source.replaceAll(">\\s*?\r*?\n*?\u0085*?\u2028*?\u2029*?\\s*?<", "><");// 去换行符处理
        }
        Pattern p = Pattern.compile("(?<=<" + regularKey
                + ">)(.*?[\r*?\n*?\u0085*?\u2028*?\u2029*?]*?.*?)(?=</" + regularKey + ">)");
        Matcher m = p.matcher(source);
        while (m.find()) {
            result.add(m.group(0));
        }
        return result;
    }

    /**
     * 通过正则表达式获取xml指令中节点数据。
     * 
     * @param regularKey
     * @param source
     * @param replay
     * @return
     */
    private static String getRegularSingle(String regularKey, String source, boolean replay) {
        String result = null;
        if (replay) {
            source = source.replaceAll(">\\s*?\r*?\n*?\u0085*?\u2028*?\u2029*?\\s*?<", "><");// 去换行符处理
        }
        Pattern p = Pattern.compile("(?<=<" + regularKey
                + ">)(.*?[\r*?\n*?\u0085*?\u2028*?\u2029*?]*?.*?)(?=</" + regularKey + ">)");
        Matcher m = p.matcher(source);
        if (m.find()) {
            result = m.group(0);
        }
        return result;
    }
}
